#include "OP_CreateVertex.h"
#include "../Geometries/PointCloud.h"

using namespace std;
using namespace CICore;
using namespace CIGeom;
using namespace CIView;

///<************************************************************************************************************>
///<************************************* region CONSTANTS DEFINITION ******************************************>
///<************************************************************************************************************>

/***************************************************************************************************************
************************************** endregion CONSTANTS DEFINITION ******************************************
****************************************************************************************************************/






/// <summary> 
/// Constructor 
/// </summary>
/// <param name="v"> A reference to the vector that contains the four 3D views pointers </param>
CIOps::OP_CreateVertex::OP_CreateVertex (vector<CIView::View*>& v) : Operation (v), geometry (0) {
    newSelectionMode = Geometry::VERTICES_SELECTION;   
}

/// <summary> 
/// Destructor 
/// </summary>
CIOps::OP_CreateVertex::~OP_CreateVertex() {
    if (status != COMPLETED)
        delete geometry;
}










///<************************************************************************************************************>
///<**************************************** region Utility Methods ********************************************>
///<************************************************************************************************************>

/// <summary> 
/// Method called to execute directly the operation 
/// </summary>
/// <returns> The operation status </returns>
int CIOps::OP_CreateVertex::Exec() {
    switch (status) {
        case INITIAL:
            status = WAITING_FOR_EVENTS;
            break;
    }
    return status;        
}

/// <summary> 
/// Method called to undo the operation 
/// </summary>
void CIOps::OP_CreateVertex::Undo() {
    status = UNDO;   
    
    scene.RemoveGeometry (geometry->GetName().c_str());     //Removes the geometry from the 3D scene

    RestoreOldSelection();                                  //Restores the old selection status    
    UpdateViews();                                          //Updates the 3D views
}

/// <summary> 
/// Method called to redo the operation 
/// </summary>
void CIOps::OP_CreateVertex::Redo() {
    status = COMPLETED;    

    scene.AddGeometry (geometry);                       //Re-adds the geometry in the 3D scene  

    RestoreNewSelection();                              //Restore the new selectio status
    UpdateViews();                                      //Updates the 3D views
}

/// <summary> 
/// Mouse Pressed event handler, called whenever the operation 
/// is in execution and a 3D view intercepts a mouse press event
/// </summary>
/// <param name="view"> The view that has thrown the event </param>
/// <param name="e"> Mouse Pressed event </param>
void CIOps::OP_CreateVertex::MousePressEvent (CIView::View* view, QMouseEvent* e) {
    SaveOldSelection();                          //Saves the old selection status 
    scene.DeselectAllFaces();                    //Deselects all faces       //TODO -> Deselect all (included geometries and groups)

    scene.SetSelectionMode (newSelectionMode);

    UpdateViews();                                  //Updates the 3D views
}

/// <summary> 
/// Mouse Released event handler, called whenever the operation 
/// is in execution and a 3D view intercepts a mouse release event
/// </summary>
/// <param name="view"> The view that has thrown the event </param>
/// <param name="e"> Mouse Released event </param>
void CIOps::OP_CreateVertex::MouseReleaseEvent (CIView::View* view, QMouseEvent* e) {
    float x = e->x();
    float y = e->y();
    
    view->WindowToWorldCoordinates (&x, &y);        //Unproject the mouse cursor coordinates

    Orientation& cameraOrient = view->GetCameraOrientation();

    Vertex* v = new Vertex();

    //Computing the vertex coordinates according to the current camera of the view that has thrown the event
    switch (view->GetCameraType()) {
        case Camera::TOP:
            v->x = x;
            v->z = y;
            break;
        
        case Camera::FRONT:
            v->x = x;
            v->y = -y;
            break;
        
        case Camera::RIGHT:            
            v->y = -y;
            v->z = -x;
            break;
         
        //case Camera::USER:
        //    //TODO
        //    //la z corrisponde (pi� o meno) alla y quando camera->orientation.x > 20 e < 150
        //    //la z corrisponde (pi� o meno) alla x quando camera->orientation.y > 20 e < 150
        //    //si pu� fare una specia di interpolazione
        //    float c = cos (float (cameraOrient.y)) * sin (float (cameraOrient.x));
        //    float s = sin (float (cameraOrient.y)) * cos (float (cameraOrient.x));

        //    v->x = x;
        //    v->y = -y;
        //    //v->z = (-x*s + y*c);
        //    break;
    }
       
                                 
    unsigned int id = scene.GenerateNewGeometryID();        //Gets a reference to the number of geometries that have been added to the scene
    stringstream name;
    name << "Vertex" << id; 
    geometry = new PointCloud (name.str());                 //Creates the new geometry
    geometry->AddVertex (v);                                //Adds the vertex to the geometry
    scene.AddGeometry (geometry);                           //Adds the new geometry in the scene
    
    status = COMPLETED;                                     //Sets the operation status to COMPLETED 
    
    view->SetPrimitivesSelected (true);                     //Signals that there is a primitive selected

    SaveNewSelection();                                     //Saves the new selection status  

    UpdateViews();                                          //Updates the 3D views  
}

/// <summary> 
/// Mouse Moved event handler, called whenever the operation 
/// is in execution and a 3D view intercepts a mouse move event
/// </summary>
/// <param name="view"> The view that has thrown the event </param>
/// <param name="e"> Mouse Moved event </param>
void CIOps::OP_CreateVertex::MouseMoveEvent (CIView::View* view, QMouseEvent* e) {
}

/// <summary> 
/// Wheel event handler, called whenever the operation 
/// is in execution and a 3D view intercepts a mouse wheel event
/// </summary>
/// <param name="view"> The view that has thrown the event </param>
/// <param name="e"> Wheel event </param>
void CIOps::OP_CreateVertex::WheelEvent (CIView::View* view, QWheelEvent* e) {
}
/***************************************************************************************************************
***************************************** endregion Utility Methods ********************************************
****************************************************************************************************************/


